package com.example.file.service.impl;


import com.example.file.exception.ServiceException;
import com.example.file.model.SysFile;
import com.example.file.response.Response;
import com.example.file.response.ResultEnum;
import com.example.file.service.SysFileService;
import com.example.file.utils.FfmpegUtils;
import com.example.file.utils.FileTypeUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysFileServiceImpl implements SysFileService {


    @SneakyThrows
    @Override
    public ResponseEntity<Resource> downloadFile(String path, Boolean handleFlag)  {
        File file = new File(path);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }

        // 对文件名进行 URL 编码
        //java会把空格编码成+，而js则是%20，这里处理一下
        String encodedFileName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8)
                .replaceAll("\\+", "%20");

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFileName);
        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);

        Resource resource;
        if (Boolean.TRUE.equals(handleFlag)) {
            byte[] videoData = FfmpegUtils.ffmpegCopyVideo(path, 5, TimeUnit.MINUTES);
            resource = new ByteArrayResource(videoData);
            headers.setContentLength(videoData.length);
        } else {
            resource = new FileSystemResource(file);
            headers.setContentLength(file.length());
        }

        return ResponseEntity.ok()
                .headers(headers)
                .body(resource);
    }
    @SneakyThrows
    @Override
    public List<SysFile> listFiles(String path) {
        if (path == null) {
            return getRootDir();
        }

        Path currentPath = Paths.get(path);
        if (!Files.exists(currentPath) || !Files.isDirectory(currentPath)) {
            return Collections.emptyList();
        }

        File file = new File(path);

        File[] files = file.listFiles();
        if (files == null || files.length < 1) {
            return Collections.emptyList();
        }

        return Arrays.stream(files)
                .sorted(Comparator.comparing(File::lastModified).reversed())
                .map(item -> {
                    SysFile sysFile = new SysFile();
                    sysFile.setFileName(item.getName());
                    sysFile.setPath(item.getAbsolutePath());
                    sysFile.setRootFlag(false);
                    sysFile.setFileType(FileTypeUtil.getFileType(item.getAbsolutePath()));
                    return sysFile;
                }).collect(Collectors.toList());
    }

    private List<SysFile> getRootDir() {
        // 获取当前文件系统
        FileSystem fs = FileSystems.getDefault();

        // 获取根目录列表
        Iterable<Path> rootDirectories = fs.getRootDirectories();

        List<SysFile> sysFiles = new ArrayList<>();

        for (Path root : rootDirectories) {

            SysFile sysFile = new SysFile();
            sysFile.setFileName(root.toString());
            sysFile.setPath(root.toString());
            sysFile.setRootFlag(true);
            sysFile.setFileType(1);
            sysFiles.add(sysFile);
        }
        return sysFiles;
    }

    @SuppressWarnings("all")
    @Override
    public Mono<Response<?>> uploadFile(FilePart file, String path) {

        return DataBufferUtils.join(file.content())
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    DataBufferUtils.release(dataBuffer);
                    return bytes;
                }).map(fileBytes -> {
                    if (fileBytes == null) {
                        throw new ServiceException(ResultEnum.EXCEPTION.getCode(), "文件不存在");
                    }

                    File filePath = new File(path);
                    if (!filePath.exists()) {
                        return Response.fail(ResultEnum.EXCEPTION.getCode(), "文件路径不存在", null);
                    }
                    try {
                        Files.write(Path.of(path + File.separator + file.filename()), fileBytes);
                        return Response.success();
                    } catch (AccessDeniedException e) {
                        return Response.fail(ResultEnum.EXCEPTION.getCode(), String.format("对%s没有操作权限", path), null);
                    } catch (IOException e) {
                        return Response.fail(ResultEnum.EXCEPTION.getCode(), e.getMessage(), null);
                    }
                });

    }
}
